package cn.jolyoulu.common.web.limiting;

import cn.jolyoulu.common.core.algorithms.flowcontrol.LeakyBucket;
import cn.jolyoulu.common.web.excption.GlobalException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Author: JolyouLu
 * @Date: 2025/11/18 14:27
 * @Version 1.0
 */
@Slf4j
@Aspect
@Component
public class CurrentLimitingAspect {

    private final static ConcurrentHashMap<String, LeakyBucket> map = new ConcurrentHashMap<>();

    @Pointcut("@annotation(cn.jolyoulu.common.web.limiting.CurrentLimiting)")
    public void currentLimitingCut() {}

    @Around("currentLimitingCut()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        //获取到对应方法上的ReqRedisLock注解
        Class<?> targetClass = pjp.getTarget().getClass();
        String methodName = pjp.getSignature().getName();
        Class[] parameterTypes = ((MethodSignature) pjp.getSignature()).getParameterTypes();
        Method method = targetClass.getMethod(methodName, parameterTypes);
        CurrentLimiting annotation = method.getAnnotation(CurrentLimiting.class);
        String id = annotation.id();
        //id为空的不管
        if (StringUtils.isBlank(id)){
            return pjp.proceed();
        }
        int capacity = annotation.capacity();
        int rate = annotation.rate();
        LeakyBucket leakyBucket = map.get(id);
        if (Objects.isNull(leakyBucket)){
            leakyBucket = new LeakyBucket(capacity,rate);
            map.putIfAbsent(id,leakyBucket);
        }
        //申请令牌
        if (leakyBucket.acquire(1)){
            return pjp.proceed();
        }else {
            throw new GlobalException(500,"网络繁忙");
        }
    }
}
